package routes

import (
	"crypto/sha256"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"os"
	"strconv"

	// "net/http"

	"go-copyright/configs" //引入configs包
	"go-copyright/dbs"     //引入数据dbs包
	"go-copyright/eths"    //引入操作以太坊eths包
	"go-copyright/utils"   //引入通用函数utils包

	"github.com/labstack/echo"

	"github.com/gorilla/sessions"
	"github.com/labstack/echo-contrib/session"
)

const PAGE_MAX_PIC = 5

/**
用户注册
请求数据 | json:email,identity_id,username
响应数据 | json:errno,errmsg
**/
func Register(c echo.Context) error {
	//响应数据，结构初始化
	var resp utils.Resp
	resp.Errno = utils.RECODE_OK
	defer utils.ResponseData(c, &resp)

	//解析数据
	account := &dbs.Account{}
	if err := c.Bind(account); err != nil {
		resp.Errno = utils.RECODE_PARAMERR
		return err
	}

	//操作geth创建账户
	address, err := eths.NewAcc(account.IdentityID, configs.Config.Eth.Connstr)
	if err != nil {
		resp.Errno = utils.RECODE_IPCERR
		return err
	}

	//操作mysql插入数据
	//sql:insert into account (email,username,identity_id,address) values (1,2,3,4)
	sql := fmt.Sprintf("insert into account (email,username,identity_id,address) values ('%s','%s','%s','%s')",
		account.Email,
		account.UserName,
		account.IdentityID,
		address)
	fmt.Println(sql)
	_, err = dbs.Create(sql)
	if err != nil {
		resp.Errno = utils.RECODE_DBERR
		return err
	}

	//写入session
	sess, _ := session.Get("session", c)
	sess.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   86400 * 7, //one day * 7
		HttpOnly: true,
	}
	sess.Values["address"] = address
	sess.Save(c.Request(), c.Response())

	return nil
}

/**
用户登录
请求数据	| json:identity_id,username
响应数据	| json:errno,errmsg
**/
func Login(c echo.Context) error {
	//响应数据，结构初始化
	var resp utils.Resp
	resp.Errno = utils.RECODE_OK
	defer utils.ResponseData(c, &resp)

	//解析数据
	account := &dbs.Account{}
	if err := c.Bind(account); err != nil {
		resp.Errno = utils.RECODE_PARAMERR
		return err
	}

	//操作mysql查询语句
	//sql:select * from account where username='yekai23' and identity_id = 'yekai23'
	sql := fmt.Sprintf("select * from account where username='%s' and identity_id = '%s'",
		account.UserName,
		account.IdentityID)
	fmt.Println(sql)
	m, n, err := dbs.DBQuery(sql)
	if err != nil || n <= 0 {
		fmt.Println("failed to query account", err)
		resp.Errno = utils.RECODE_DBERR
		return err
	}
	rows := m[0]

	//写入session
	sess, _ := session.Get("session", c)
	sess.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   86400 * 7, //one day * 7
		HttpOnly: true,
	}
	sess.Values["address"] = rows["address"]
	sess.Save(c.Request(), c.Response())

	return nil
}

/**
用户上传图片
请求数据	| json:form中文件二进制数据
响应数据	| json:errno,errmsg
**/
func Upload(c echo.Context) error {
	//响应数据，结构初始化
	var resp utils.Resp
	resp.Errno = utils.RECODE_OK
	defer utils.ResponseData(c, &resp)

	//解析数据(文件数据)
	content := &dbs.Content{}
	h, err := c.FormFile("fileName")
	if err != nil {
		fmt.Println("failed to FormFile", err)
		resp.Errno = utils.RECODE_DBERR
		return err
	}
	src, err := h.Open()
	defer src.Close()

	content.Content = "static/photo/" + h.Filename
	dst, err := os.Create(content.Content)
	if err != nil {
		fmt.Println("failed to create file", err, content.Content)
		resp.Errno = utils.RECODE_IOERR
		return err
	}
	defer dst.Close()

	//计算hash
	cDate := make([]byte, h.Size)
	n, err := src.Read(cDate)
	if err != nil || h.Size != int64(n) {
		resp.Errno = utils.RECODE_IOERR
		return err
	}
	content.Content_hash = fmt.Sprintf("%x", sha256.Sum256(cDate))
	dst.Write(cDate)
	content.Title = h.Filename

	//操作mysql新增数据
	content.AddContent()

	//操作以太坊
	sess, _ := session.Get("session", c)
	fromAddr, ok := sess.Values["address"].(string)
	if fromAddr == "" || !ok {
		resp.Errno = utils.RECODE_SESSIONERR
		return errors.New("no session")
	}
	go eths.UploadPic(fromAddr, "yekai23", content.Content_hash, content.Title)

	return nil
}

/**
查看所有用户图片
请求数据	| 无
响应数据	| json:{Errno,Errmsg,Data:{total_page,current_page,contents:[]}}
**/
func GetPics(c echo.Context) error {

	//"select a.content_hash,title,token_id from content a,account_content b where a.content_hash=b.content_hash and address=''"

	//响应数据
	var resp utils.Resp
	resp.Errno = utils.RECODE_OK
	defer utils.ResponseData(c, &resp)

	//处理session
	sess, err := session.Get("session", c)
	if err != nil {
		fmt.Println("failed to get session")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}
	address := sess.Values["address"]
	if address == nil {
		fmt.Println("failed to get session,address is nil")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}
	//查询数据库
	sql := fmt.Sprintf("select a.content_hash,title,token_id from content a,account_content b where a.content_hash=b.content_hash and address='%s'", address)
	fmt.Printf(sql)
	contents, num, err := dbs.DBQuery(sql)
	if err != nil || num <= 0 {
		fmt.Println("failed to query GetPics", err)
		resp.Errno = utils.RECODE_DBERR
		return err
	}

	total_page := int(num)/PAGE_MAX_PIC + 1
	current_page := 1
	mapResp := make(map[string]interface{})
	mapResp["total_page"] = total_page
	mapResp["current_page"] = current_page
	mapResp["contents"] = contents

	resp.Data = mapResp

	return nil
}

/**
获取单个图片
**/
func GetPic(c echo.Context) error {
	content := &dbs.Content{}
	content.Title = c.Param("title")
	fmt.Println("get title", content.Title)
	//最好查数据库获得路径
	content.Content = "static/photo/" + content.Title
	http.ServeFile(c.Response(), c.Request(), content.Content)
	return nil
}

/**
开始拍卖
请求数据	| json:{content_hash,percent,price,token_id}
响应数据	| json:errno,errmsg
**/
func GoAuction(c echo.Context) error {
	//响应数据，结构初始化
	var resp utils.Resp
	resp.Errno = utils.RECODE_OK
	defer utils.ResponseData(c, &resp)

	//解析数据
	auction := &dbs.Auction{}
	if err := c.Bind(auction); err != nil {
		resp.Errno = utils.RECODE_PARAMERR
		return err
	}

	//从session获取address
	sess, err := session.Get("session", c)
	if err != nil {
		fmt.Println("failed to get session")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}
	address, ok := sess.Values["address"].(string)
	if address == "" || !ok {
		fmt.Println("failed to get session,address is nil")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}
	auction.Address = address

	//操作mysql新增语句
	//sql:insert into auction(content_hash,address,token_id,percent,price,status) values ()
	sql := fmt.Sprintf("insert into auction(content_hash,address,token_id,percent,price,status) values ('%s','%s','%d','%d','%d',0)",
		auction.Content_hash,
		auction.Address,
		auction.TokenID,
		auction.Percent,
		auction.Price)
	fmt.Println(sql)
	_, err = dbs.Create(sql)
	if err != nil {
		fmt.Println("failed to insert auction", err)
		resp.Errno = utils.RECODE_DBERR
		return err
	}

	return nil
}

/**
查看拍卖
请求数据	| 无
响应数据	| json:{errno,errmsg,data:[{price,title,token_id,content_hash}]}
**/
func GetAuctions(c echo.Context) error {

	//"select a.content_hash,title,token_id from content a,account_content b where a.content_hash=b.content_hash and address=''"

	//响应数据
	var resp utils.Resp
	resp.Errno = utils.RECODE_OK
	defer utils.ResponseData(c, &resp)

	//处理session
	sess, err := session.Get("session", c)
	if err != nil {
		fmt.Println("failed to get session")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}
	address := sess.Values["address"]
	if address == nil {
		fmt.Println("failed to get session,address is nil")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}
	//查询数据库
	sql := fmt.Sprintf("select a.content_hash,title,price,token_id from content a,auction b where a.content_hash=b.content_hash and address <> '%s'", address)
	fmt.Printf(sql)
	auctions, _, err := dbs.DBQuery(sql)
	if err != nil {
		fmt.Println("failed to query auctions", err)
		resp.Errno = utils.RECODE_DBERR
		return err
	}

	resp.Data = auctions

	return nil
}

/**
结束拍卖
请求数据	| price,tokenid
响应数据	| json:{errno,errmsg}
**/
func BidAuction(c echo.Context) error {
	//组织响应数据
	var resp utils.Resp
	resp.Errno = utils.RECODE_OK
	defer utils.ResponseData(c, &resp)

	//获取传参
	price := c.QueryParam("price")
	tokenid := c.QueryParam("tokenid")
	if price == "" || tokenid == "" {
		fmt.Println("failed to get price or tokenid")
		resp.Errno = utils.RECODE_PARAMERR
		return errors.New("param not found")
	}

	//session
	sess, err := session.Get("session", c)
	if err != nil {
		fmt.Println("failed to get session")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}
	address := sess.Values["address"].(string)
	if address == "" {
		fmt.Println("failed to get session,address is nil")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}

	//数据库操作 - 修改使拍卖结束(更新操作)
	//sql: update auction set price =111,status=1 where token_id = 0;
	sql := fmt.Sprintf("update auction set price ='%s',status=1 where token_id = '%s'", price, tokenid)
	_, err = dbs.Create(sql)
	if err != nil {
		fmt.Println("failed to update auction ", err)
		resp.Errno = utils.RECODE_DBERR
		return err
	}
	//查询weight->percent和address
	sql = fmt.Sprintf("select percent,address from auction where token_id='%s'", tokenid)
	mData, num, err := dbs.DBQuery(sql)
	if num <= 0 || err != nil {
		fmt.Println("failed to query auction ", err)
		resp.Errno = utils.RECODE_DBERR
		return err
	}
	weight := mData[0]["percent"]
	seller := mData[0]["address"]

	//启动协程(操作以太坊 - 分割资产，erc20转账)
	go func() {
		_tokenid, _ := strconv.ParseInt(tokenid, 10, 32)
		_price, _ := strconv.ParseInt(price, 10, 32)
		_weight, _ := strconv.ParseInt(weight, 10, 32)
		//分割资产
		err := eths.EthSplitAsset(configs.Config.Eth.Foundation, "yekai23", address, _tokenid, _weight)
		if err != nil {
			fmt.Println("failed to call EthSplitAsset ", err)
			return
		}
		//ERC20转账
		err = eths.EthTransfer20(address, "yekai23", seller, _price)
		if err != nil {
			fmt.Println("failed to call EthTransfer20 ", err)
			return
		}
	}()

	return nil
}

/**
照片投票
**/
func VotePic(c echo.Context) error {
	//组织响应数据
	var resp utils.Resp
	resp.Errno = utils.RECODE_OK
	defer utils.ResponseData(c, &resp)

	//获取传参
	vote_info := c.QueryParam("vote_info")

	m := make(map[string]interface{})

	err := json.Unmarshal([]byte(vote_info), &m)

	if err != nil {
		fmt.Println(err)
	}
	_content_hash := m["content_hash"]

	fmt.Println("content_hash------>", _content_hash)

	if _content_hash == "" {
		fmt.Println("failed to get vote info")
		resp.Errno = utils.RECODE_PARAMERR
		return errors.New("param not found")
	}

	//session
	sess, err := session.Get("session", c)
	if err != nil {
		fmt.Println("failed to get session")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}
	address := sess.Values["address"].(string)
	if address == "" {
		fmt.Println("failed to get session,address is nil")
		resp.Errno = utils.RECODE_SESSIONERR
		return err
	}

	//操作mysql新增语句
	//sql:insert into vote(vote_id,address,content_hash) values ()
	sql := fmt.Sprintf("insert into vote(address,content_hash) values ('%s','%s')",
		address,
		_content_hash)
	fmt.Println(sql)
	_, err = dbs.Create(sql)
	if err != nil {
		fmt.Println("failed to insert vote", err)
		resp.Errno = utils.RECODE_DBERR
		return err
	}

	return nil

}
